package com.ybear.citypickerview;

import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.alibaba.fastjson.JSONArray;
import com.ybear.citypickerview.adapter.CityListAdapter;
import com.ybear.citypickerview.entity.CityData;
import com.ybear.citypickerview.entity.CityEntity;
import com.ybear.citypickerview.entity.CityPickerData;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/**
 * 城市选择器
 */
public class CityPickerView extends LinearLayout {
    public interface OnSelectDataChangeListener {
        void onDataChange(CityPickerView view, CityData data, int branch);
    }
    public interface OnSelectDataListener {
        void onData(CityPickerView view, CityPickerData data);
    }
    public interface OnSelectBranchListener {
        void onBranch(CityPickerView view, int branch, int maxBranch);
    }

    private DialogRecyclerView drvListView;
    private LinearLayout lSelectCityGroup;

    //当前分支。0：省、1：市、2：区/县、3：街道（其实就是下标）
    private int curBranch = 0;
    //最大分支
    private int maxBranch = 4;
    //所有点击的分支。[maxBranch][0：新分支（选中的分支）、1：旧分支（上一个选中的分支）]
    private int[][] positions = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} };
    private String[] defSelectCityNames = { "请选择省份", "请选择城市", "请选择区/县", "请选择街道" };
    private CityData[] selectCityData = new CityData[ maxBranch ];

    //选中的文本颜色
    private int selectCityTextColorResId = getResources().getColor( R.color.colorPrimary );
    //选择城市的Flag图标资源id
    private int selectFlagImgResId, unSelectFlagImgResId;
    //选择城市的Flag图标宽高
    private int flagWidth, flagHeight;

    //完整的数据源列表
    private List<CityEntity> fullList;
    //当前分支的数据源列表
    private List<CityEntity> currentList;
    //列表适配器
    private CityListAdapter mAdapter;
    private TextStyleBuild selectCityStyle;
    private OnSelectDataChangeListener mOnSelectDataChangeListener;
    private OnSelectDataListener mOnSelectDataListener;
    private OnSelectBranchListener mOnSelectBranchListener;

    public CityPickerView(Context context) {
        super(context);
        init();
    }

    public CityPickerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CityPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    private void init() {
        initView();
        initData();
        initListener();
    }

    /**
     * 初始化组件
     */
    private void initView() {
        lSelectCityGroup = new LinearLayout( getContext() );
        drvListView = new DialogRecyclerView( getContext() );


        lSelectCityGroup.setLayoutParams(
                new ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT
                )
        );
        drvListView.setLayoutParams(
                new ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT
                )
        );

        setOrientation( VERTICAL );
        lSelectCityGroup.setOrientation( VERTICAL );
        lSelectCityGroup.setBackgroundResource( R.drawable.layer_btm_line );
        drvListView.setLayoutManager( new LinearLayoutManager( getContext() ) );
        drvListView.setBackgroundResource( R.color.colorWhile );

        addView( lSelectCityGroup );
        addView( drvListView );
    }

    /**
     * 初始化数据
     */
    private void initData() {
        flagHeight = flagWidth = dp2Px(getContext(), 10);
        //读取所有城市的数据
        fullList = JSONArray.parseArray( getFullData() ).toJavaList( CityEntity.class );

        currentList = new ArrayList<>( fullList );
        mAdapter = new CityListAdapter( currentList );
        drvListView.setAdapter( mAdapter );

        //处理选择城市按钮的点击事件
        doSelectCityClick(0);
    }

    /**
     * 初始化监听器
     */
    private void initListener() {
        mAdapter.setOnItemClickListener((view, baseViewHolder, cityEntity, i) -> {
            //处理Item点击事件
            doItemClick(cityEntity, i);
        });
    }

    /* ****************************************************************** */

    /**
     * 设置默认的选择城市名称
     * @param province  默认省份
     * @param city      默认城市
     * @param county    默认区/县
     * @param street    默认街道
     */
    public void setDefaultSelectCityNames(@Nullable String province, @Nullable String city,
                                          @Nullable String county, @Nullable String street) {
        String[] names = { province, city, county, street };
        TextView  tv;
        for (int i = 0; i < defSelectCityNames.length; i++) {
            if( names[i] != null ) {
                defSelectCityNames[i] = names[i];
                tv = getSelectCityView( i );
                if( tv != null ) tv.setText( names[i] );
            }
        }
    }

    /**
     * 设置选择城市的文本颜色
     * @param resId     颜色资源id
     */
    public void setSelectCityTextColor(@ColorRes int resId) {
        selectCityTextColorResId = getResources().getColor( resId );
    }

    /**
     * 设置选择Item的文本颜色
     * @param resId     颜色资源id
     */
    public void setSelectItemTextColor(@ColorRes int resId) {
        mAdapter.setSelectTextColor( resId );
    }

    /**
     * 设置未选择Item的文本颜色
     * @param resId     颜色资源id
     */
    public void setUnSelectItemTextColor(@ColorRes int resId) {
        mAdapter.setUnSelectTextColor( resId );
    }

    /**
     * 设置选择的Flag图标，不设置默认隐藏{@link View#INVISIBLE}
     * @param resId     资源id
     */
    public void setSelectFlag(@DrawableRes int resId) {
        selectFlagImgResId = resId;
    }

    /**
     * 设置未选择的Flag图标，不设置默认隐藏{@link View#INVISIBLE}
     * @param resId     资源id
     */
    public void setUnSelectFlag(@DrawableRes int resId) {
        unSelectFlagImgResId = resId;
        //初始化省份的默认Flag
        setSelectFlagImg( 0, false );
    }

    /**
     * 设置选择城市的Flag高度和高度
     * @param width     宽度
     * @param height    高度
     */
    public void setFlagSize(int width, int height) {
        flagWidth = width;
        flagHeight = height;
        setFlagSize(getFlagView(curBranch), width, height);
    }
    public void setFlagSize(int size) { setFlagSize(size, size); }

    /**
     * 设置选择城市的背景资源
     * @param resId     资源id
     */
    public void setSelectCityBackgroundResource(int resId) {
        lSelectCityGroup.setBackgroundResource( resId );
    }

    /**
     * 设置选择城市的样式
     * @param build     样式
     */
    public void setSelectCityStyle(TextStyleBuild build) {
        selectCityStyle = build;
        setTextStyle( getSelectCityView( 0 ), build );
    }

    /**
     * 设置Item的样式
     * @param build     样式
     */
    public void setItemStyle(TextStyleBuild build) {
        mAdapter.setItemTextStyle(item -> setTextStyle(item.getTitle(), build));
    }

    /**
     * 设置选择的数据回调监听器，数据将会在选择完最后一项时回调
     * @param listener  监听器
     */
    public void setOnSelectDataListener(@NonNull OnSelectDataListener listener) {
        mOnSelectDataListener = listener;
    }

    /**
     * 设置选择的实时数据回调监听器，数据会在每一项选择时动态回调
     * @param listener  监听器
     */
    public void setOnSelectDataChangeListener(@NonNull OnSelectDataChangeListener listener) {
        mOnSelectDataChangeListener = listener;
    }

    /**
     * 设置选择的分支回调监听器
     * @param listener  监听器
     */
    public void setOnSelectBranchListener(OnSelectBranchListener listener) {
        mOnSelectBranchListener = listener;
    }

    public DialogRecyclerView getDialogRecyclerView() {
        return drvListView;
    }

    /**
     * 获取列表适配器
     * @return  适配器
     */
    public CityListAdapter getAdapter() {
        return mAdapter;
    }

    /* ****************************************************************** */

    /**
     * 处理Item点击事件
     * @param data      选择城市按钮的实体类
     * @param position  选中Item的位置
     */
    private void doItemClick(CityEntity data, int position) {
        String name = data.getName();
        String code = data.getCode();
        positions[curBranch][1] = positions[curBranch][0];
        positions[curBranch][0] = position;
        //回调实时数据
        callSelectDataChange(curBranch, code, name);
        //选择最后一项时回调数据
        if( curBranch == maxBranch - 1 ) callSelectDataAll();
        //设置选中城市按钮的文本内容
        setSelectCityViewText( curBranch, name);
        //显示选中城市图标
        setSelectFlagImg(curBranch, true);
        //设置当前选中的Item点击样式
        setSelectItemTouchStyle();
        //设置选中城市的点击效果为选中状态
        setSelectCityTouchStyle();
        //添加选择城市的按钮
        if( curBranch < maxBranch - 1 ) {
            curBranch++;
            doSelectCityClick( curBranch );
            setBranchData();
        }
        //如果当前分支的数量只有一个，则自动进入当前Item（递归进入只有一个Item的列表）
        if( currentList.size() == 1 ) {
            doItemClick(currentList.get(0), 0);
        }
    }

    /**
     * 处理选择城市按钮的点击事件
     * @param branch    分支
     */
    private void doSelectCityClick(int branch) {
        View v = createSelectCityView(defSelectCityNames[branch], unSelectFlagImgResId, branch);
        lSelectCityGroup.addView( v );

        v.setOnClickListener(view -> {
            curBranch = (int) view.getTag();
            //滑动到的位置
            int scrollPosition = positions[curBranch][0];
            //删除所有下级分支的按钮
            while ( lSelectCityGroup.getChildCount() > curBranch + 1 ) {
                lSelectCityGroup.removeViewAt( lSelectCityGroup.getChildCount() - 1 );
            }
            //设置当前分支的数据
            setBranchData();
            //设置当前选中的Item点击样式
            setSelectItemTouchStyle();
            //设置当前的点击效果为选中状态
            setSelectCityTouchStyle();
            //滑动到选择的位置
            drvListView.smoothScrollToPosition( scrollPosition < 0 ? 0 : scrollPosition );
        });
    }

    /**
     * 初始化位置
     * 初始化范围在分支和最大范围之间
     * @param branch    分支
     */
    private void initPositions(int branch) {
        if( branch < 0 || branch > positions.length - 1 ) return;
        for (int i = branch; i < positions.length; i++) {
            setItemSelect(positions[i][0], false);
            setItemSelect(positions[i][1], false);
            positions[i][0] = -1;
            positions[i][1] = -1;
        }
    }

    /**
     * 设置选择的Flag图标
     * @param branch    分支
     * @param select    是否选中。会根据该参数调用两个资源id
     *                  {@link #selectFlagImgResId}、{@link #unSelectFlagImgResId}
     */
    private void setSelectFlagImg(int branch, boolean select) {
        ImageView iv = getFlagView(branch);
        //设置过flag图标的选择状态才能显示
        if( iv == null ) return;
        if( select ) {
            if( selectFlagImgResId != 0 ) iv.setImageResource( selectFlagImgResId );
        }else {
            if( unSelectFlagImgResId != 0 ) iv.setImageResource( unSelectFlagImgResId );
        }
    }

    /**
     * 设置当前选中的Item
     * @param branch    当前分支
     * @param select    是否被选中
     */
    private void setItemSelect(int branch, boolean select) {
        if( branch > -1 && branch < currentList.size() ) {
            currentList.get( branch ).setSelect( select );
        }
    }

    /**
     * 根据不同分支设置数据
     */
    private void setBranchData() {
        List<CityEntity> newList = null;
        int prov = positions[0][0];
        int city = positions[1][0];
        int coun = positions[2][0];

        switch ( curBranch ) {
            case 0: //省
                newList = new ArrayList<>( fullList );
                break;
            case 1: //市
                if( prov == -1 ) return;
                newList = fullList.get( prov ).getChildren();
                break;
            case 2: //区/县
                if( prov == -1 || city == -1 ) return;
                newList = fullList.get( prov ).getChildren().get( city ).getChildren();
                break;
            case 3://街道
                if( prov == -1 || city == -1 || coun == -1 ) return;
                newList = fullList.get( prov ).getChildren()
                        .get( city ).getChildren()
                        .get( coun ).getChildren();
                break;
        }
        if( newList != null ) {
            initPositions( curBranch + 1 );
            currentList.clear();
            currentList.addAll( newList );
            mAdapter.notifyDataSetChanged();
        }
    }

    /**
     * 设置当前选中的Item点击样式
     */
    private void setSelectItemTouchStyle() {
        //取消所有选中的Item
        for ( CityEntity e : currentList ) e.setSelect( false );
        //选中当前的Item
        setItemSelect(positions[curBranch][0], true);
        //更新
        mAdapter.notifyDataSetChanged();
    }

    /**
     * 设置选中城市的点击效果
     */
    private void setSelectCityTouchStyle() {
        TextView tv;
        //先取消所有选中的按钮颜色
        for (int i = 0; i < lSelectCityGroup.getChildCount(); i++) {
            tv = getSelectCityView( i );
            if( tv != null ) {
                int color = selectCityStyle != null &&
                        ( color = selectCityStyle.getTextColor() ) != 0 ?
                        color : R.color.colorBlack;
                tv.setTextColor(getResources().getColor( color ));
            }
        }
        //设置选中的颜色
        tv = getSelectCityView( curBranch );
        if( tv != null ) tv.setTextColor( selectCityTextColorResId );
    }

    /**
     * 设置选中城市按钮的文本内容
     * @param branch    分支
     * @param text      文本
     */
    private void setSelectCityViewText(int branch, String text) {
        TextView tv = getSelectCityView( branch );
        if( tv != null ) tv.setText( text );
    }

    /**
     * 设置选择城市图标的大小
     * @param iv        flag
     * @param width     宽度
     * @param height    高度
     */
    private void setFlagSize(ImageView iv, int width, int height) {
        if( iv == null ) return;
        LinearLayout.LayoutParams lp = (LayoutParams) iv.getLayoutParams();
        lp.height = height;
        lp.width = width;
        iv.setLayoutParams( lp );
    }

    /**
     * 获取选中城市的按钮
     * @param branch    分支
     * @return          {@link TextView}
     */
    @Nullable
    private TextView getSelectCityView(int branch) {
        if( branch > lSelectCityGroup.getChildCount() ) return null;
        return (TextView)
                ((LinearLayout) lSelectCityGroup.getChildAt( branch )).getChildAt(1);
    }

    /**
     * 获取选中城市的图标
     * @param branch    分支
     * @return          {@link ImageView}
     */
    @Nullable
    private ImageView getFlagView(int branch) {
        if( branch > lSelectCityGroup.getChildCount() ) return null;
        return (ImageView) ((LinearLayout)
                lSelectCityGroup.getChildAt( branch )).getChildAt(0);
    }

    /**
     * 回调实时选择的数据
     * @param branch    数据源的分支
     * @param code      数据code
     * @param name      数据名
     */
    private void callSelectDataChange(int branch, String code, String name) {
        if( branch < 0 || branch > maxBranch ) return;
        //存储当前选择的数据
        selectCityData[ branch ] = new CityData(code, name);
        //回调当前数据
        if( mOnSelectDataChangeListener != null ) {
            mOnSelectDataChangeListener.onDataChange( this, selectCityData[branch], branch );
        }
        //回调当前分支
        if( mOnSelectBranchListener != null ) {
            mOnSelectBranchListener.onBranch(this, branch, maxBranch);
        }
    }

    private void callSelectDataAll() {
        if( mOnSelectDataListener == null ) return;
        mOnSelectDataListener.onData(this, new CityPickerData()
                .setProvince( selectCityData[0] )
                .setCity( selectCityData[1] )
                .setCounty( selectCityData[2] )
                .setStreet( selectCityData[3] )
        );
    }


    /**
     * 创建选中城市组件
     * @param name          名称
     * @param flagResId     图标id
     * @param branch        当前组件的分支
     * @return              {@link View}
     */
    private View createSelectCityView(String name, @DrawableRes int flagResId, int branch) {
        View v = LayoutInflater.from( getContext() )
                .inflate(R.layout.item_select_city, lSelectCityGroup, false);
        TextView tvName = v.findViewById(R.id.item_select_city_tv_name);
        ImageView ivFlag = v.findViewById(R.id.item_select_city_iv_flag);
        v.setLayoutParams(new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT)
        );
        setFlagSize(ivFlag, flagWidth, flagHeight);
        tvName.setText( name );

        if( flagResId != 0 ) ivFlag.setImageResource( flagResId );
        v.setFocusable( true );
        v.setClickable( true );
        //当前选择View的分支（省、市...）
        v.setTag( branch );
        setTextStyle( tvName, selectCityStyle );
        return v;
    }

    private void setTextStyle(TextView tv, TextStyleBuild build) {
        if( build == null ) return;
        int color = build.getTextColor();
        int gravity = build.getGravity();
        int bg = build.getBackgroundResource();
        int[] padding = build.getPadding();
        Typeface tf = build.getTypeface();

        tv.setTextSize( build.getTextSizeUnit(), build.getTextSize() );
        if( color != 0 ) tv.setTextColor( getResources().getColor( color ) );
        if( tf != null ) tv.setTypeface( tf );
        if( bg != 0 ) tv.setBackgroundResource( bg );
        tv.setGravity( gravity );
        if( padding != null ) tv.setPadding( padding[0], padding[1], padding[2], padding[3] );
    }

    /**
     * 获取完整数据
     * @return  数据源
     */
    private String getFullData() {
        String fileName = "pca_data.json";
        StringBuilder sb = new StringBuilder();
        InputStreamReader isr;
        BufferedReader br;
        int len;
        try {
            isr = new InputStreamReader( getContext().getAssets().open( fileName ) );
            br = new BufferedReader( isr );
            while ( ( len = br.read() ) != -1 ) {
                sb.append( (char) len );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }


    /**
     * dp转px
     * @param mContext      上下文
     * @param dp            dip值
     * @return              返回的px值
     */
    private int dp2Px(@Nullable Context mContext, int dp) {
        if( mContext == null ) return dp;
        final float scale = mContext.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }
}
